import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.ECGenParameterSpec;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * Description:
 * Date:        2023-03-15 16:58
 * author:      ysj
 * version:     V1.0
 */
public class CreateSm2Key {

    public static void main(String[] args) {

        //SM2 sm2 = SmUtil.sm2();
        UUID uuid = UUID.randomUUID();
        // 获取当前日期
        Date currentDate = new Date();
        // 创建SimpleDateFormat对象，指定日期格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        // 格式化日期
        String formattedDate = dateFormat.format(currentDate);

        String code = SmUtil.sm3("WD202310-10001.docx");

        System.out.println(code);

        String key = "guid=" + uuid + "filename=xml_test.xml" + "path=uploadXml/WD202310-10001"
                + "securitylevel=0" + "synctime="+formattedDate + "srcappid=photos" + "srcappname=电源研究所TDM3.0系统"
                + "destappid=tdm" + "destappname=内网端tdm" + "checkcode=" + code + "signature=" + "reserved=18";

        String test = "guid=ab2b3ba9-9c34-44af-8c9d-55e400d0151efilename=WD202310-10001.docxpath=uploadXml/WD202310-10001securitylevel=0synctime=20231120111926srcappid=tdmsrcappname=电源研究所TDM3.0系统destappid=tdmdestappname=内网端tdmcheckcode=1063102e3738ad681e94dc693973c23c86c5375a1e853465d970d08bd9f09614signature=reserved=18";

        Base64 base64 = new Base64();
        KeyPair kp = generateSm2KeyPair();
        String priKey = base64.encode( kp.getPrivate().getEncoded() );
        String pubKey = base64.encode( kp.getPublic().getEncoded() );

//        System.out.println("----输出生成的公钥私钥-----");
//        System.out.println("priKey："+ priKey);
//        System.out.println("pubKey："+ pubKey);

        //私钥加签
        System.out.println("----私钥加签-----");
        String sign = sign(test, "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg7AlmL4mM4B+DTzz+3+l1xzvlx0t+14U8n6cMBXhUf/agCgYIKoEcz1UBgi2hRANCAARp6abfc/UB2YrPS5MzKu8EDuzqjGZmkOExyISSQU9MKDKBe1W0DaPZzp5ST01keGKT4nbhhi7eyXOGO8zOmUEb");
        System.out.println("签名输出："+sign);

        //公钥验签
        System.out.println("----公钥验签-----");
        boolean result = verify(test, sign, "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEaemm33P1AdmKz0uTMyrvBA7s6oxmZpDhMciEkkFPTCgygXtVtA2j2c6eUk9NZHhik+J24YYu3slzhjvMzplBGw==");
        System.out.println("验签结果："+result);
    }

    public static KeyPair generateSm2KeyPair() {
        try {
            final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");

            // 获取一个椭圆曲线类型的密钥对生成器
            final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
            SecureRandom random = new SecureRandom();

            // 使用SM2的算法区域初始化密钥生成器
            kpg.initialize(sm2Spec, random);

            // 获取密钥对
            KeyPair keyPair = kpg.generateKeyPair();
            return keyPair;
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return null;
    }

    public static String sign( String content, String priKey) {
        SM2 sm2 = new SM2(priKey, null);
        sm2.usePlainEncoding();
        String sign = sm2.signHex(HexUtil.encodeHexStr(content));
        return sign;
    }

    public static boolean verify(String content, String sign, String publicKey) {

        try {
            SM2 sm2 = new SM2(null, publicKey);
            sm2.usePlainEncoding();
            boolean verify = sm2.verifyHex(HexUtil.encodeHexStr(content), sign);
            return verify;
        }catch(Exception e) {
            e.printStackTrace();
            return false;
        }
    }

}